package com.scheduler.backend.aps.domain.deadlinefirst;

import com.scheduler.backend.aps.domain.Resource;
import com.scheduler.backend.aps.domain.ResourceGroup;
import com.scheduler.backend.aps.domain.Shift;
import lombok.*;

import java.util.*;

/**
 * @author heimingz
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EmployeeArrangement {
    List<ResourceGroup> employeeGroups;

    /**
     * TODO: 待优化
     *
     * @param targetNum      目标资源数
     * @param resourceGroups 资源组
     * @return 资源安排候选方案
     */
    public static List<EmployeeArrangement> getCandidates(Long targetNum, List<ResourceGroup> resourceGroups) {
        List<EmployeeArrangement> candidates = new ArrayList<>();

        List<ResourceGroup> backupGroups = new ArrayList<>();
        for (ResourceGroup group : resourceGroups) {
            backupGroups.add(new ResourceGroup(group.getResourceId(), group.getResourceType(),
                    group.getAmount(), group.getResources()));
        }

        // 根据排班将资源组分类
        Map<Shift, List<ResourceGroup>> shiftGroups = new HashMap<>();
        for (ResourceGroup group : backupGroups) {
            if (group.getResources() == null || group.getResources().size() == 0) {
                continue;
            }
            Shift shift = group.getResources().get(0).getShift();
            if (shiftGroups.containsKey(shift)) {
                shiftGroups.get(shift).add(group);
            } else {
                List<ResourceGroup> groups = new ArrayList<>();
                groups.add(group);
                shiftGroups.put(shift, groups);
            }
        }

        // 获取每个排班的排列组合
        for (List<ResourceGroup> groups : shiftGroups.values()) {
            candidates.addAll(getSimpleSplit(targetNum, groups));
        }

        return candidates;
    }

    private static List<EmployeeArrangement> getSimpleSplit(Long targetNum, List<ResourceGroup> groups) {
        List<EmployeeArrangement> candidates = new ArrayList<>();

        // 拆分
        int splitNum = targetNum.intValue();
        List<ResourceGroup> splitGroups = new ArrayList<>();
        for (ResourceGroup group : groups) {
            while (group.getAmount() > splitNum) {
                List<Resource> resources = group.getResources();
                ResourceGroup newGrp = new ResourceGroup(group.getResourceId(), group.getResourceType(),
                        (long) splitNum, resources.subList(0, splitNum));
                splitGroups.add(newGrp);

                group.setAmount(group.getAmount() - splitNum);
                group.setResources(resources.subList(splitNum, resources.size()));
            }
            splitGroups.add(group);
        }

        // 组合
        splitGroups.sort(Comparator.comparingLong(ResourceGroup::getAmount).reversed());
        List<ResourceGroup> employeeGroups = new ArrayList<>();
        Long total = 0L;
        for (ResourceGroup group : splitGroups) {
            if (group.getAmount() >= targetNum) {
                candidates.add(new EmployeeArrangement(Collections.singletonList(group)));
                continue;
            }
            employeeGroups.add(group);
            total += group.getAmount();
            if (total >= targetNum) {
                candidates.add(new EmployeeArrangement(employeeGroups));
                employeeGroups = new ArrayList<>();
                total = 0L;
            }
        }

        return candidates;
    }
}